package main

import "fmt"

// --- 基本函数定义 ---
// 函数可以接受零个或多个参数。
// 参数类型在参数名之后。
// 函数可以返回零个或多个结果。
func greet(name string) {
    fmt.Println("你好,", name)
}

// --- 带返回值的函数 ---
// 返回值类型在参数列表之后。
func add(a int, b int) int {
    return a + b
}

// --- 多个参数和多个返回值 ---
// Go 函数可以返回多个值，这非常常用于返回结果和错误。
func divmod(a, b int) (int, int) {
    return a / b, a % b
}

// --- 命名返回值 ---
// 可以为返回值命名，这相当于在函数内部声明了变量。
// 使用 return 语句时，会自动返回这些命名变量的当前值。
// 这能让代码更清晰，尤其是在短函数中。
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    // 等价于 return x, y
    return
}

// --- 可变参数函数 ---
// 可以接受任意数量的参数。
// 可变参数必须是函数的最后一个参数。
// 在函数内部，可变参数的类型是一个切片。
func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}

// --- 函数作为值 ---
// 在 Go 中，函数也是一种类型，可以作为参数传递给其他函数，或者作为其他函数的返回值。
func applyFunc(f func(int, int) int, a, b int) int {
    return f(a, b)
}

// --- 闭包 ---
// 闭包是一个函数值，它引用了其函数体之外的变量。
// 该函数可以访问并赋予其引用的变量的值。
func adder() func(int) int {
    sum := 0
    // 返回的匿名函数形成了一个闭包
    return func(x int) int {
        sum += x
        return sum
    }
}

func main() {
    // --- 调用基本函数 ---
    greet("小明")

    // --- 调用带返回值的函数 ---
    result := add(3, 5)
    fmt.Println("3 + 5 =", result)

    // --- 调用多返回值函数 ---
    div, mod := divmod(10, 3)
    fmt.Printf("10 除以 3: 商 = %d, 余数 = %d\n", div, mod)

    // 如果你只想要其中一个返回值，可以使用空白标识符 "_"
    _, modOnly := divmod(10, 3)
    fmt.Println("10 除以 3 的余数是:", modOnly)

    // --- 调用命名返回值函数 ---
    x, y := split(17)
    fmt.Printf("split(17) 的结果是: x = %d, y = %d\n", x, y)

    // --- 调用可变参数函数 ---
    total := sum(1, 2, 3, 4, 5)
    fmt.Println("1+2+3+4+5 =", total)

    // 也可以传递一个切片，使用 "..." 解包
    nums := []int{10, 20, 30}
    totalFromSlice := sum(nums...)
    fmt.Println("10+20+30 =", totalFromSlice)

    // --- 使用函数作为值 ---
    // 定义一个函数变量
    var myFunc func(int, int) int = add
    fmt.Println("通过函数变量调用:", myFunc(10, 20))

    // 将函数作为参数传递
    applyResult := applyFunc(func(a, b int) int { return a * b }, 5, 6)
    fmt.Println("applyFunc 的结果:", applyResult)

    // --- 使用闭包 ---
    pos, neg := adder(), adder()
    for i := 0; i < 3; i++ {
        fmt.Println(pos(i), neg(-2*i))
    }
}